;
; File     : X86_64_Windows.s
; Created  : 3 May 2011
;
; Copyright © 2011 Matthew Wilson (mj. {my-surname} .uk {at} gmail.com)
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU Lesser General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU Lesser General Public License for more details.
;
; You should have received a copy of the GNU Lesser General Public License
; along with this program.  If not, see <http://www.gnu.org/licenses/>.
;

_TEXT SEGMENT

.CODE

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Call for 1 argument                                                          ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

dni_x86_64_windows_call_1 PROC

    ; Java JNI signature is:
    ;   long      fnptr
    ;   <..>      arg0
    ;
    ; Registers:
    ;   rcx:      JNIEnv*
    ;   rdx:      jclass
    ;   r8:       fnptr
    ;   r9:       arg0  \_ either
    ;   xmm3:     arg0  /    or

    ; move displaced argument
    mov       rcx, r9
    movq      xmm0, xmm3

    jmp       r8

dni_x86_64_windows_call_1 ENDP


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Call for 2 arguments                                                         ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

dni_x86_64_windows_call_2 PROC

    ; Java JNI signature is:
    ;   long      fnptr
    ;   <..>      arg0
    ;
    ; Registers:
    ;   rcx:      JNIEnv*
    ;   rdx:      jclass
    ;   r8:       fnptr
    ;   r9:       arg0  \_ either
    ;   xmm3:     arg0  /    or
    ;
    ; Stack:
    ;   rsp + 40: arg1


    ; move displaced argument
    mov       rcx, r9
    movq      xmm0, xmm3

    mov       rdx, qword ptr [ rsp + 40 ]
    movd      xmm1, rdx

    jmp       r8

dni_x86_64_windows_call_2 ENDP


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Call for 3 arguments                                                         ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

dni_x86_64_windows_call_3 PROC

    ; Java JNI signature is:
    ;   long      fnptr
    ;   <..>      arg0
    ;   <..>      arg1
    ;
    ; Registers:
    ;   rcx:      JNIEnv*
    ;   rdx:      jclass
    ;   r8:       fnptr
    ;   r9:       arg0  \_ either
    ;   xmm3:     arg0  /    or
    ;
    ; Stack:
    ;   rsp + 40: arg1
    ;   rsp + 48: arg2


    ; preserve function pointer
    mov       r10, r8

    ; move displaced argument
    mov       rcx, r8
    movq      xmm0, xmm3

    mov       rdx, qword ptr [ rsp + 40 ]
    mov       r8,  qword ptr [ rsp + 48 ]
    movd      xmm1, rdx
    movd      xmm2, r8

    jmp       r10

dni_x86_64_windows_call_3 ENDP


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Call for 4 arguments                                                         ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

dni_x86_64_windows_call_4 PROC

    ; Java JNI signature is:
    ;   long      fnptr
    ;   <..>      arg0
    ;   <..>      arg1
    ;   <..>      arg2
    ;
    ; Registers:
    ;   rcx:      JNIEnv*
    ;   rdx:      jclass
    ;   r8:       fnptr
    ;   r9:       arg0  \_ either
    ;   xmm3:     arg0  /    or
    ;
    ; Stack:
    ;   rsp + 40: arg1
    ;   rsp + 48: arg2
    ;   rsp + 56: arg3


    ; preserve function pointer
    mov       r10, r8

    ; move displaced argument
    mov       rcx, r9
    movq      xmm0, xmm3

    mov       rdx, qword ptr [ rsp + 40 ]
    mov       r8,  qword ptr [ rsp + 48 ]
    mov       r9,  qword ptr [ rsp + 56 ]
    movd      xmm1, rdx
    movd      xmm2, r8
    movd      xmm3, r9

    jmp       r10

dni_x86_64_windows_call_4 ENDP


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Call for >4 arguments                                                        ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

dni_x86_64_windows_call_displace_4 PROC

    ; Java JNI signature is:
    ;   long      fnptr
    ;   <..>      arg0
    ;   <..>      arg1
    ;   <..>      arg2
    ;   <..>      arg3
    ;
    ; Registers:
    ;   rcx:      JNIEnv*
    ;   rdx:      jclass
    ;   r8:       fnptr
    ;   r9:       offset
    ;
    ; Stack:
    ;   rsp + 40     : arg4...
    ;   rsp + r9 +  0: arg0
    ;   rsp + r9 +  8: arg1
    ;   rsp + r9 + 16: arg2
    ;   rsp + r9 + 24: arg3


    ; preserve function pointer
    mov       r10, r8

    ; locate displaced arguments
    add       r9, rsp

    ; retrieve displaced arguments
    mov       rcx, qword ptr [ r9 +  0 ]
    mov       rdx, qword ptr [ r9 +  8 ]
    mov       r8,  qword ptr [ r9 + 16 ]
    mov       r9,  qword ptr [ r9 + 24 ]
    movd      xmm0, rcx
    movd      xmm1, rdx
    movd      xmm2, r8
    movd      xmm3, r9

    jmp       r10

dni_x86_64_windows_call_displace_4 ENDP


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Call for 'n' arguments                                                       ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

dni_x86_64_windows_call_n PROC

    ; Java JNI signature is:
    ;   long      fnptr
    ;   long      argptr
    ;   int       argcount
    ;
    ; Registers:
    ;   rcx:      JNIEnv*
    ;   rdx:      jclass
    ;   r8:       fnptr
    ;   r9:       argptr
    ;
    ; Stack:
    ;   rsp + 40: count (in 64-bit units)


    ; prologue
    push      rbp
    mov       rbp, rsp
    push      rsi
    push      rdi

    ; preserve function pointer
    mov       rax, r8

    ; retrieve arg count
    mov       rcx, qword ptr [ rbp + 8 + 40 ]

    ; allocate stack for call
    lea       rdi, qword ptr [ 0 + 8 * rcx ]
    sub       rsp, rdi

    ; copy the spill arguments (all but the first four)
    lea       rsi, qword ptr [ r9  + 32 ]
    lea       rdi, qword ptr [ rsp + 32 ]
    sub       rcx, 4
    rep movsq

    ; retrieve the register arguments
    mov       rcx, qword ptr [ r9 +  0 ]
    mov       rdx, qword ptr [ r9 +  8 ]
    mov       r8,  qword ptr [ r9 + 16 ]
    mov       r9,  qword ptr [ r9 + 24 ]
    movd      xmm0, rcx
    movd      xmm1, rdx
    movd      xmm2, r8
    movd      xmm3, r9

    call      rax

    ; clean the stack
    lea       rsp, [ rbp - 16 ]

    ; epilogue
    pop       rdi
    pop       rsi
    mov       rsp, rbp
    pop       rbp

    ret

dni_x86_64_windows_call_n ENDP


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

_TEXT ENDS

END
